package com.org.devg.dbcluster;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.PlatformTransactionManager;

@AutoConfigureAfter(DevgDataSourceConfiguration.class)
@EnableConfigurationProperties(DevgDbclusterConfig.class)
@Configuration
public class DevgMybatisConfiguration {

  private static Logger log = LoggerFactory.getLogger(DevgMybatisConfiguration.class);

  public static final Map<String, String> dataSourceMap = new ConcurrentHashMap<>();

  public static final String dataSourceType = "dataSourceType";

  private final DevgDbclusterConfig devgDbclusterConfig;

  public DevgMybatisConfiguration(DevgDbclusterConfig devgDbclusterConfig) {
    this.devgDbclusterConfig = devgDbclusterConfig;
  }

  @Autowired
  @Qualifier("masterDataSource")
  private DataSource masterDataSource;

  @Autowired
  @Qualifier("slaveDataSource")
  private DataSource slaveDataSource;

  @Bean(name = "sqlSessionFactory")
  public SqlSessionFactory sqlSessionFactorys() {
    try {
      SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
      sessionFactoryBean.setDataSource(roundRobinDataSouceProxy());
      // 读取配置
      sessionFactoryBean.setTypeAliasesPackage(devgDbclusterConfig.getMybatisConfig().getBasePackage());
      //设置mapper.xml文件所在位置
      Resource[] resources = new PathMatchingResourcePatternResolver()
          .getResources(devgDbclusterConfig.getMybatisConfig().getMapperLocations());
      sessionFactoryBean.setMapperLocations(resources);
      //设置mybatis-config.xml配置文件位置
      sessionFactoryBean.setConfigLocation(
          new DefaultResourceLoader().getResource(devgDbclusterConfig.getMybatisConfig().getConfigLocation()));
      //添加分页插件、打印sql插件
      return sessionFactoryBean.getObject();
    } catch (IOException e) {
      log.error("mybatis resolver mapper*xml is error", e);
      return null;
    } catch (Exception e) {
      log.error("mybatis sqlSessionFactoryBean create error", e);
      return null;
    }
  }

  /**
   * 把所有数据库都放在路由中
   *
   * @return
   */
  @Bean(name = "roundRobinDataSouceProxy")
  public AbstractRoutingDataSource roundRobinDataSouceProxy() {
    Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
    targetDataSources.put("masterDataSource", masterDataSource);
    targetDataSources.put("slaveDataSource", slaveDataSource);
    AbstractRoutingDataSource proxy = new AbstractRoutingDataSource() {
      @Override
      protected Object determineCurrentLookupKey() {
        String dsType = dataSourceMap.get(dataSourceType);
        if (null == dsType || dsType.equals("")) {
          dsType = "masterDataSource";
          dataSourceMap.putIfAbsent(dataSourceType, dsType);
        }
        log.info("use DataSource:"+dsType);
        return dsType;
      }
    };
    proxy.setDefaultTargetDataSource(masterDataSource);
    proxy.setTargetDataSources(targetDataSources);
    return proxy;
  }

  @Bean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    return new SqlSessionTemplate(sqlSessionFactory);
  }

  //事务管理
  @Bean
  public PlatformTransactionManager annotationDrivenTransactionManager() {
    return new DataSourceTransactionManager(roundRobinDataSouceProxy());
  }

}
